<template >
  <el-drawer
    :visible.sync="visible"
    direction="btt"
    size="100%"
    style="position: absolute"
    :modal="false"
    :before-close="handleClose"
    :show-close="showClose"
    @open="onOpen"
    @opened="onOpened"
    @close="onClose"
    @closed="onClosed"
  >
    <!-- 调用el-drawer组件的具名插槽title -->
    <template #title>
      <slot name="title">
        <span role="heading" :title="title">{{ title }}</span>
      </slot>
    </template>
    <el-scrollbar style="height: 100%">
      <section :style="drawerBodyStyle">
        <el-table
          ref="multipleTable"
          :data="permissionTree"
          :default-expand-all="true"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
          row-key="id"
          highlight-current-row
          style="width: 100%"
          @select-all="onSelectAll"
          @select="onSelect"
        >
          <el-table-column type="selection" width="50" />
          <el-table-column prop="name" label="导航菜单" width="200" />
          <el-table-column label="菜单操作" width>
            <template #default="{ row }">
              <el-checkbox-group
                v-if="row.operations && row.operations.length > 0"
                v-model="chekedOperations"
              >
                <el-checkbox
                  v-for="operation in row.operations"
                  :key="operation.id"
                  :label="operation.id"
                  @change="(value) => onChange(value, row.id)"
                  >{{ operation.name }}</el-checkbox
                >
              </el-checkbox-group>
            </template>
          </el-table-column>
        </el-table>
      </section>
    </el-scrollbar>
    <div class="drawer-footer" v-if="showFooter">
      <slot name="footer">
        <el-button size="mini" @click.native="onCancel">取消</el-button>
        <el-button type="primary" size="mini" @click.native="onSave"
          >确定</el-button
        >
      </slot>
    </div>
    <div v-else></div>
  </el-drawer>
</template>
<script>
import {
  getPermissions,
  getTenantPermissions,
  saveTenantPermission,
  getRolePermissions,
  saveRolePermission,
} from "@/api/permission";
import { treeToList, getTreeParents } from "@/utils/tree";
export default {
  name: "GrantPermission",
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
    title: {
      type: String,
      default: "",
    },
    drawerBodyStyle: {
      type: String,
      default: "padding:24px 48px 74px 24px;",
    },
    showClose: {
      type: Boolean,
      default: true,
    },
    showFooter: {
      type: Boolean,
      default: true,
    },
    closeAfterSave: {
      type: Boolean,
      default: true,
    },
    roleId: {
      type: Number,
      default: 0,
    },
    tenantId: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      permissionTree: [],
      checkedPermissions: [], //选中的权限菜单,用于保存
      chekedOperations: [],
    };
  },
  mounted() {
    this.getPermissions();
  },
  methods: {
    getPermissions() {
      getPermissions({}).then((data) => {
        this.permissionTree = data;
        this.bindPermissions();
      });
    },
    bindPermissions() {
      if (!(this.roleId || this.tenantId)) {
        return;
      }
      if (this.roleId) {
        getRolePermissions({ roleId: this.roleId }).then((data) => {
          setPermissions(data);
        });
      } else {
        getTenantPermissions({ tenantId: this.tenantId }).then((data) => {
          setPermissions(data);
        });
      }

      const setPermissions = (data) => {
        this.chekedOperations = data.operationPermissionIds;

        const menuPermissionIds = data.menuPermissionIds;
        //所有的权限
        const allPermissions = treeToList(this.permissionTree);
        allPermissions.forEach((row) => {
          const checked = menuPermissionIds.includes(row.id);
          this.$refs.multipleTable.toggleRowSelection(row, checked);
        });

        this.checkedPermissions = this.$refs.multipleTable.selection.map(
          (s) => {
            return s.id;
          }
        );
      };
    },
    onSelectAll(selection) {
      //已被选中的权限
      const selections = treeToList(selection);
      //所有的权限
      const allPermissions = treeToList(this.permissionTree);

      const checked = selections.length === allPermissions.length;
      allPermissions.forEach((row) => {
        this.$refs.multipleTable.toggleRowSelection(row, checked);
        this.selectOperations(row, checked);
      });

      this.checkedPermissions = this.$refs.multipleTable.selection.map((s) => {
        return s.id;
      });
    },
    onSelect(selection, row) {
      //判断当前行是否被选中
      const checked = selection.some((s) => s.id === row.id);
      if (row.children) {
        const rows = treeToList(row.children);
        rows.forEach((r) => {
          this.$refs.multipleTable.toggleRowSelection(r, checked);
          this.selectOperations(r, checked);
        });
      } else {
        this.selectOperations(row, checked);
      }

      const parents = getTreeParents(this.permissionTree, row.id);
      parents.forEach((parent) => {
        const checked = this.checkedPermissions.includes(parent.id);
        if (!checked) {
          this.$refs.multipleTable.toggleRowSelection(parent, true);
        }
      });

      this.checkedPermissions = this.$refs.multipleTable.selection.map((s) => {
        return s.id;
      });
    },
    selectOperations(row, checked) {
      if (row.operations) {
        row.operations.forEach((operation) => {
          const index = this.chekedOperations.indexOf(operation.id);
          if (checked) {
            if (index === -1) {
              this.chekedOperations.push(operation.id);
            }
          } else {
            if (index > -1) {
              this.chekedOperations.splice(index, 1);
            }
          }
        });
      }
    },
    onChange(value, id) {
      const parents = getTreeParents(this.permissionTree, id);
      parents.forEach((parent) => {
        const checked = this.checkedPermissions.includes(parent.id);
        if (!checked) {
          this.$refs.multipleTable.toggleRowSelection(parent, value);
        }
      });
      this.checkedPermissions = this.$refs.multipleTable.selection.map((s) => {
        return s.id;
      });
    },
    handleClose() {
      this.onCancel();
    },
    onOpen() {
      this.getPermissions();
    },
    onOpened() {
      this.$emit("onOpened");
    },
    onClose() {
      this.$emit("close");
    },
    onClosed() {
      this.$emit("onClosed");
    },
    onCancel() {
      this.checkedPermissions = [];
      this.chekedOperations = [];
      this.$refs.multipleTable.clearSelection();
      //Vue中的数据是单向数据流：父级 prop 的更新会向下流动到子组件中，但是反过来则不行，即子组件无法直接修改父组件中的数据。
      // 但我们常常会遇到需要在子组件中修改父组件数据的场景。.sync修饰符就可以帮助我们实现这种功能。
      this.$emit("update:visible", false);
    },
    onSave() {
      if (!(this.roleId || this.tenantId)) {
        this.$message({
          message: "请选择设置权限的目标",
          type: "warning",
        });
        return;
      }
      const permissionIds = this.checkedPermissions.concat(
        this.chekedOperations
      );
      if (this.roleId) {
        saveRolePermission({
          roleId: this.roleId,
          permissionIds: permissionIds,
        }).then(() => {
          if (this.closeAfterSave) {
            this.onCancel();
          }
        });
      } else {
        saveTenantPermission({
          tenantId: this.tenantId,
          permissionIds: permissionIds,
        });
      }
    },
  },
};
</script>
<style lang="" >
</style>